package com.wisewin.pose.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.wisewin.pose.api.controller.WechatController;
import com.wisewin.pose.config.dto.ResultDTO;
import com.wisewin.pose.config.dto.ResultDTOBuilder;
import com.wisewin.pose.dao.UserDAO;
import com.wisewin.pose.dao.UserPhysicalActionDAO;
import com.wisewin.pose.dao.UserPhysicalActionScoreDAO;
import com.wisewin.pose.dao.UserPhysicalActionTrendDAO;
import com.wisewin.pose.dao.UserPhysicalFitnessDAO;
import com.wisewin.pose.dao.UserPhysicalHealthDAO;
import com.wisewin.pose.dao.UserPhysicalRecordDAO;
import com.wisewin.pose.entity.bo.QueryParamBO;
import com.wisewin.pose.entity.db.OrgUserPhysicalRecordDO;
import com.wisewin.pose.entity.db.UserDO;
import com.wisewin.pose.entity.db.UserPhysicalActionDO;
import com.wisewin.pose.entity.db.UserPhysicalActionScoreDO;
import com.wisewin.pose.entity.db.UserPhysicalActionTrendDO;
import com.wisewin.pose.entity.db.UserPhysicalFitnessDO;
import com.wisewin.pose.entity.db.UserPhysicalHealthDO;
import com.wisewin.pose.entity.db.UserPhysicalRecordDO;
import com.wisewin.pose.entity.dto.ActionMultTrendDTO;
import com.wisewin.pose.entity.dto.ActionTrendDTO;
import com.wisewin.pose.entity.dto.MultTrendDTO;
import com.wisewin.pose.entity.dto.TrendDTO;
import com.wisewin.pose.util.PageInfo;
import com.wisewin.pose.util.PageObjectUtil;
import com.wisewin.pose.util.PageUtil;
import com.wisewin.pose.util.ScoreUtil;
import com.wisewin.pose.util.wechatOffice.string.StringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class UserPhysicalRecordService {

    final static Logger log = LoggerFactory.getLogger(WechatController.class);

    @Autowired
    private UserPhysicalRecordDAO userPhysicalRecordDAO;
    @Autowired
    private UserPhysicalHealthDAO userPhysicalHealthDAO;
    @Autowired
    private UserPhysicalActionDAO userPhysicalActionDAO;
    @Autowired
    private UserPhysicalFitnessDAO userPhysicalFitnessDAO;
    @Autowired
    private UserPrescriptionService userPrescriptionService;
    @Autowired
    private UserPhysicalActionScoreDAO userPhysicalActionScoreDAO;
    @Autowired
    private UserPhysicalActionTrendDAO userPhysicalActionTrendDAO;
    @Autowired
    private UserDAO userDAO;

    public UserDO queryUserById(Integer id) {
        return userDAO.queryUserById(id);
    }

    // 机构的报告模糊搜索
    @SuppressWarnings("rawtypes")
    public ResultDTO wildcardSearchPhysicalRecordsByOrgId(QueryParamBO query, PageUtil pageUtil) {
        Map<String, Object> param = new HashMap<>();
        param.put("orgId", query.getOrgId());
        param.put("userName", query.getUserName());
        param.put("startTime", query.getStartTime());
        param.put("endTime", query.getEndTime());
        param.put("pageOffset", pageUtil.getPageNo());
        param.put("pageSize", pageUtil.getPageSize());
        List<OrgUserPhysicalRecordDO> recordDOs = userPhysicalRecordDAO.wildcardSearchRecords(param);
        PageObjectUtil page = new PageObjectUtil();
        int pageSize = userPhysicalRecordDAO.countwildcardSearchUserRecords(param);
        PageInfo pageData = page.savePageObject(pageSize, recordDOs, pageUtil);
        return ResultDTOBuilder.success(pageData);
    }

    // 查询用户报告列表
    @SuppressWarnings("rawtypes")
    public ResultDTO queryPhysicalRecords(QueryParamBO query, PageUtil pageUtil) {
        Map<String, Object> param = new HashMap<>();
        param.put("userId", query.getUserId());
        param.put("pageOffset", pageUtil.getPageNo());
        param.put("pageSize", pageUtil.getPageSize());
        List<UserPhysicalRecordDO> recordDOs = userPhysicalRecordDAO.queryRecordsByUsrId(param);
        PageObjectUtil page = new PageObjectUtil();
        int pageSize = userPhysicalRecordDAO.countUserRecords(query.getUserId());
        PageInfo pageData = page.savePageObject(pageSize, recordDOs, pageUtil);
        return ResultDTOBuilder.success(pageData);
    }

    // 查询机构下:某个用户报告列表
    @SuppressWarnings("rawtypes")
    public ResultDTO queryOrgUserPhysicalRecords(QueryParamBO query, PageUtil pageUtil) {
        Map<String, Object> param = new HashMap<>();
        param.put("orgId", query.getOrgId());
        param.put("userId", query.getUserId());
        param.put("pageOffset", pageUtil.getPageNo());
        param.put("pageSize", pageUtil.getPageSize());
        List<OrgUserPhysicalRecordDO> recordDOs = userPhysicalRecordDAO.queryRecordsByUsrIdAndOrgId(param);
        PageObjectUtil page = new PageObjectUtil();
        int pageSize = userPhysicalRecordDAO.countUserRecords(query.getUserId());
        PageInfo pageData = page.savePageObject(pageSize, recordDOs, pageUtil);
        return ResultDTOBuilder.success(pageData);
    }

    public MultTrendDTO queryMultTrendDTO(List<UserPhysicalRecordDO> recordDates,
            UserPhysicalRecordDO userPhysicalRecordDO) {
        // 总活动度
        List<Integer> motionRangeScore = recordDates.stream().mapToInt(UserPhysicalRecordDO::getMotionRangeScore)
                .boxed().collect(Collectors.toList());
        List<ActionMultTrendDTO> multiTrends = new ArrayList<>();
        ActionMultTrendDTO motionRange = new ActionMultTrendDTO();
        motionRange.setLabelName("总活动性");
        motionRange.setSeriesData(motionRangeScore);
        multiTrends.add(motionRange);
        //
        List<Integer> stabilityScore = recordDates.stream().mapToInt(UserPhysicalRecordDO::getStabilityScore)
                .boxed().collect(Collectors.toList());
        ActionMultTrendDTO stability = new ActionMultTrendDTO();
        stability.setLabelName("总稳定性");
        stability.setSeriesData(stabilityScore);
        multiTrends.add(stability);
        //
        List<Integer> symmetryScore = recordDates.stream().mapToInt(UserPhysicalRecordDO::getStabilityScore)
                .boxed().collect(Collectors.toList());
        ActionMultTrendDTO symmetry = new ActionMultTrendDTO();
        symmetry.setLabelName("总对称性");
        symmetry.setSeriesData(symmetryScore);
        multiTrends.add(symmetry);
        //
        List<Integer> overallRiskScore = recordDates.stream().mapToInt(UserPhysicalRecordDO::getOverallRiskScore)
                .boxed().collect(Collectors.toList());
        ActionMultTrendDTO overallRisk = new ActionMultTrendDTO();
        overallRisk.setLabelName("风险指数");
        overallRisk.setSeriesData(overallRiskScore);
        multiTrends.add(overallRisk);
        //
        List<Integer> overallScore = recordDates.stream().mapToInt(UserPhysicalRecordDO::getOverallScore)
                .boxed().collect(Collectors.toList());
        ActionMultTrendDTO overall = new ActionMultTrendDTO();
        overall.setLabelName("综合评分");
        overall.setSeriesData(overallScore);
        multiTrends.add(overall);

        MultTrendDTO tDto = new MultTrendDTO();
        tDto.setTrends(multiTrends);
        return tDto;
    }

    public TrendDTO queryTrendDTOByUserId(UserPhysicalRecordDO userPhysicalRecordDO) {

        // 查询动作集合
        List<UserPhysicalActionTrendDO> trendDOs = userPhysicalActionTrendDAO
                .getUserPhysicalActionTrendsByUserId(userPhysicalRecordDO.getUserId(),
                        userPhysicalRecordDO.getRecordId());
        ActionTrendDTO[] trendDTOs = new ActionTrendDTO[14];
        // Group by actionName
        Map<String, List<UserPhysicalActionTrendDO>> groupedTrends = trendDOs
                .stream().collect(Collectors.groupingBy(UserPhysicalActionTrendDO::getActionName));
        groupedTrends.entrySet().stream()
                .flatMap(entry -> {
                    String key = entry.getKey();
                    List<UserPhysicalActionTrendDO> trends = entry.getValue();
                    // Sort by recordId
                    trends.sort((t1, t2) -> t2.getRecordId() - t1.getRecordId());
                    ScoreUtil.processActionTrends(key, trends, trendDTOs);
                    return trends.stream();
                }).collect(Collectors.toList());
        TrendDTO tDto = new TrendDTO();
        tDto.setTrends(trendDTOs);
        return tDto;
    }

    // 查询报告原始数据
    public ResultDTO queryPhysicalRecord(UserPhysicalRecordDO userPhysicalRecordDO) {
        if (userPhysicalRecordDO.getRecordId() == null) {
            return ResultDTOBuilder.failure("1", "参数有误", null);
        }
        // 处理机构ID
        userPhysicalRecordDO.setOrgId(userPhysicalRecordDO.getOrgId() == null ? 1 : userPhysicalRecordDO.getOrgId());
        //
        return ResultDTOBuilder.success(userPhysicalRecordDAO.queryByRecordId(userPhysicalRecordDO.getRecordId()));
    }

    // 查询报告详情
    public ResultDTO queryPhysicalRecordDetail(UserPhysicalRecordDO userPhysicalRecordDO) {
        if (userPhysicalRecordDO.getRecordId() == null) {
            return ResultDTOBuilder.failure("1", "参数有误", null);
        }
        userPhysicalRecordDO = userPhysicalRecordDAO.queryByRecordId(userPhysicalRecordDO.getRecordId());
        if (userPhysicalRecordDO == null) {
            return ResultDTOBuilder.failure("1", "当前报告不存在", null);
        }
        // 查询动作集合
        List<UserPhysicalActionDO> actions = userPhysicalActionDAO
                .queryActionsByRecordId(userPhysicalRecordDO.getRecordId());
        userPhysicalRecordDO.setLstAction(actions);
        // 查询分数集合
        List<UserPhysicalFitnessDO> scores = userPhysicalFitnessDAO
                .getByRecordId(userPhysicalRecordDO.getRecordId());
        userPhysicalRecordDO.setLstFitness(scores);
        // 查询分数集合
        List<UserPhysicalActionScoreDO> actionScores = userPhysicalActionScoreDAO
                .getByRecordId(userPhysicalRecordDO.getRecordId());
        userPhysicalRecordDO.setLstActionScore(actionScores);
        // 查询趋势
        List<UserPhysicalRecordDO> recordDates = userPhysicalActionTrendDAO
                .getRecordsDates(userPhysicalRecordDO.getUserId(), userPhysicalRecordDO.getRecordId());
        SimpleDateFormat f = new SimpleDateFormat("MM.dd");
        // 格式化时间
        List<String> dates = recordDates.stream().map(r -> f.format(r.getCreateTime()))
                .collect(Collectors.toList());
        TrendDTO trendDTO = queryTrendDTOByUserId(userPhysicalRecordDO);
        trendDTO.setDates(dates);
        userPhysicalRecordDO.setTrend(trendDTO);
        // 多趋势数据
        MultTrendDTO multTrend = queryMultTrendDTO(recordDates, userPhysicalRecordDO);
        multTrend.setDates(dates);
        userPhysicalRecordDO.setMultTrend(multTrend);
        // 查询用户信息
        UserDO dbUser = queryUserById(userPhysicalRecordDO.getUserId());
        if (dbUser == null) {
            return ResultDTOBuilder.failure("1", "用户不存在", null);
        }
        userPhysicalRecordDO.setHeadimgurl(dbUser.getHeadimgurl());
        userPhysicalRecordDO.setSex(dbUser.getSex());
        userPhysicalRecordDO.setUserName(dbUser.getUserName());
        userPhysicalRecordDO.setPhone(dbUser.getPhone());

        return ResultDTOBuilder
                .success(userPhysicalRecordDO);
    }

    // 查询动作列表数据
    public ResultDTO queryActionsByRecordId(UserPhysicalRecordDO userPhysicalRecordDO) {
        return ResultDTOBuilder.success(userPhysicalActionDAO
                .queryActionsByRecordId(userPhysicalRecordDO.getRecordId()));
    }

    public ResultDTO saveUserPhysicalRecord(UserPhysicalRecordDO userPhysicalRecordDO) {
        if (StringUtils.isEmpty(userPhysicalRecordDO.getOriginalData())) {
            return ResultDTOBuilder.failure("1", "参数有误", null);
        }
        // 处理机构ID
        userPhysicalRecordDO.setOrgId(userPhysicalRecordDO.getOrgId() == null ? 1 : userPhysicalRecordDO.getOrgId());
        // 添加数据
        userPhysicalRecordDAO.insert(userPhysicalRecordDO);
        // 处理体态评估数据
        dealUserPhysicalRecord(userPhysicalRecordDO.getRecordId(), userPhysicalRecordDO);
        // 生成方案
        userPrescriptionService.dealUserPrescription(userPhysicalRecordDO.getRecordId());
        return ResultDTOBuilder.success(userPhysicalRecordDO);
    }

    public void dealUserPhysicalRecord(Integer recordId, UserPhysicalRecordDO userPhysicalRecordDO) {
        String originalData = userPhysicalRecordDO.getOriginalData();
        if (StringUtils.isEmpty(originalData)) {
            return;
        }
        // 处理数据
        Map<String, JSONObject> resultMap = JSON.parseObject(userPhysicalRecordDO.getOriginalData(),
                new TypeReference<HashMap<String, JSONObject>>() {
                });
        // 评估建议
        Map<String, Map<String, Map<String, Integer>>> bodyScores = new HashMap<>();
        // 处理分数数据
        List<UserPhysicalActionScoreDO> scoreDOs = ScoreUtil.dealUserPhysicalActionScore(recordId,
                userPhysicalRecordDO.getUserId(), resultMap, bodyScores);
        if (scoreDOs != null && scoreDOs.size() > 0) {
            userPhysicalActionScoreDAO.insertBatch(scoreDOs);
            // 处理平均值
            ScoreUtil.calcAverageScore(scoreDOs, userPhysicalRecordDO);
        }
        // 处理肌肉数据
        userPhysicalRecordDO.setMuscleData(JSONObject.toJSONString(
                ScoreUtil.dealUserMuscleDOs(recordId, userPhysicalRecordDO.getUserId(), resultMap)));
        // 体态
        Map<String, UserPhysicalHealthDO> postureScores = new HashMap<>();
        // 处理建议
        int activityScore = userPhysicalRecordDO.getMotionRangeScore();
        int stabilityScore = userPhysicalRecordDO.getStabilityScore();
        int symmetryScore = userPhysicalRecordDO.getSymmetryScore();

        // 处理动作数据
        Iterator<Map.Entry<String, JSONObject>> entries = resultMap.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, JSONObject> entry = entries.next();
            String mapKey = entry.getKey();
            Object mapValue = entry.getValue();
            // System.out.println(mapKey + ": " + mapValue);
            // 体态评估结果数据
            if ("posture".equals(mapKey)) {
                dealUserPhysicalHealth(recordId, mapValue.toString(), postureScores);
            } else {
                if (mapValue != null) {
                    List<UserPhysicalActionDO> lstAction = new ArrayList<>();
                    UserPhysicalActionDO userPhysicalActionDO = JSON.parseObject(mapValue.toString(),
                            UserPhysicalActionDO.class);
                    userPhysicalActionDO.setActionName(mapKey);
                    userPhysicalActionDO.setRecordId(recordId);
                    lstAction.add(userPhysicalActionDO);
                    if (!CollectionUtils.isEmpty(lstAction)) {
                        userPhysicalActionDAO.insertBatch(lstAction);
                    }
                }
            }
        }
        //
        String suggession = ScoreUtil.generateReport(activityScore, stabilityScore, symmetryScore, bodyScores,
                postureScores);
        userPhysicalRecordDO.setSuggestion(suggession);
        log.info("bodyScores {}  --  suggession { }  ", bodyScores, suggession);

        // 将计算的均值 肌肉数据更新到recored表
        userPhysicalRecordDAO.update(userPhysicalRecordDO);
    }

    public void dealUserPhysicalHealth(Integer recordId, String postureData,
            Map<String, UserPhysicalHealthDO> postureScores) {
        Map<String, String> categoryMap = userPhysicalCategory();
        List<String> lstCategory = new ArrayList<>();
        List<UserPhysicalHealthDO> lstHealth = new ArrayList<>();
        // 处理数据
        Map<String, Object> resultMap = JSON.parseObject(postureData, new TypeReference<HashMap<String, Object>>() {
        });
        Iterator<Map.Entry<String, Object>> entries = resultMap.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, Object> entry = entries.next();
            String mapKey = entry.getKey();
            Object mapValue = entry.getValue();
            if (mapValue != null) {
                UserPhysicalHealthDO userPhysicalHealthDO = JSON.parseObject(mapValue.toString(),
                        UserPhysicalHealthDO.class);
                postureScores.put(mapKey, userPhysicalHealthDO);
                if (!lstCategory.contains(mapKey)) {
                    userPhysicalHealthDO.setRecordId(recordId);
                    userPhysicalHealthDO.setCategory(mapKey);
                    // 处理类型名称
                    userPhysicalHealthDO.setCategoryName(categoryMap.get(mapKey));
                    lstHealth.add(userPhysicalHealthDO);
                    lstCategory.add(userPhysicalHealthDO.getCategory());
                }
            }
        }
        if (!CollectionUtils.isEmpty(lstHealth)) {
            userPhysicalHealthDAO.insertBatch(lstHealth);
        }
    }

    public Map<String, String> userPhysicalCategory() {
        Map<String, String> categoryMap = new HashMap<>();
        categoryMap.put("headLateral", "头部侧倾");
        categoryMap.put("hlShoulder", "高低肩");
        categoryMap.put("bodyTilt", "躯干偏移");
        categoryMap.put("pelvicTilt", "骨盆侧倾");
        categoryMap.put("leftLeg", "左腿评估");
        categoryMap.put("rightLeg", "右腿盖评估");
        return categoryMap;
    }
}
